package com.autotest.sync.utils;

import java.io.File;
import java.io.IOException;
import java.net.Socket;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import com.android.ddmlib.AndroidDebugBridge;
import com.android.ddmlib.AndroidDebugBridge.IClientChangeListener;
import com.android.ddmlib.IDevice;
import com.android.ddmlib.AndroidDebugBridge.IDeviceChangeListener;
import com.autotest.sync.stf.DeviceInfo;
import com.google.common.base.Joiner;
import com.google.common.base.Strings;

/**
 * adb帮助类，提供adb的所有操作能力
 * 
 * @author thomas-ning
 * @version 2015年6月9日 下午1:08:48
 */
public class ADBHelper {
	private static Logger logger = LogManager.getLogger(ADBHelper.class.getSimpleName());
	public static AndroidDebugBridge bridge = null;
	public static String ADBpath = null;
	// 暂时adb常态化命令
	public static String adbps = "adb -s deviceId shell ps";
	public static String killPID = "adb -s deviceId shell kill ";
	public static String cmdDevicePorp = "adb -s deviceId shell getprop";
	public static String cmdWireless = "adb connect ";
	public static String cmdScreenSize = "adb -s deviceId shell wm size"; //获取屏幕大小
	public static String cmdForwardPort = "adb -s deviceId forward tcp:%s tcp:%s";
	public static String cmdForwardPortLocalabstract = "adb -s deviceId forward tcp:%s localabstract:%s";
	public static String cmdAdbProp = "adb -s deviceId shell getprop";//获取设备属性
	public static String viewPackage = "adb -s deviceId shell pm list package";//获取设备属性
	public static String cmdClearPort = "adb forward --remove-all"; //清除所有端口
	public static String cmdInstall = "adb -s deviceId install -r \"%s\""; //安装apk
	
	// end
	static {

		AndroidDebugBridge.init(false);
		initADB();
		bridge = AndroidDebugBridge.createBridge(ADBpath, false);
		waitDeviceList();

	}

	// 静态初如化类
	private static boolean initADB() {

		String osName = System.getProperty("os.name");
		String android_home = System.getenv("ANDROID_HOME");
		if(android_home == null){
			logger.warn("未设置android_home");
			ADBpath = "adb";
			return false;
		}
		String adbPath = android_home.replaceAll("\\\\", "/")
				+ "/platform-tools";
		String adb = osName.matches("(?i)windows.*") ? "adb.exe" : "adb";
		String result = adbPath + "/" + adb;
		File f = new File(result);
		if (!f.exists()) {
			ADBpath = null;
			return false;
		}
		ADBpath = result;
		return true;
	}

	public static void registerDeviceListener(
			IDeviceChangeListener iDeviceChangeListener) {
		AndroidDebugBridge.addDeviceChangeListener(iDeviceChangeListener);
	}

	public static void removeDeviceListener(
			IDeviceChangeListener iDeviceChangeListener) {
		AndroidDebugBridge.removeDeviceChangeListener(iDeviceChangeListener);
	}
	
	public static void addClinetListener(
			IClientChangeListener iClinetChangeListener) {
		AndroidDebugBridge.addClientChangeListener(iClinetChangeListener);
	}

	/**
	 * 获取目前所连接的手机终端序列号
	 * 
	 * @return
	 */
	public static String[] getDevicesName() {
		IDevice devices[] = bridge.getDevices();
		String[] devicesName = new String[devices.length];
		for (int i = 0; i < devices.length; i++) {
			devicesName[i] = devices[i].getSerialNumber();
		}
		return devicesName;

	}
	/**
	 * 获取在线设备列表
	 * @return
	 */
	public static String[] getOnlineDevices(){
		IDevice devices[] = bridge.getDevices();
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < devices.length; i++) {
			if(devices[i].isOnline()){
				sb.append(devices[i].getSerialNumber() + ",");
			}
		}
		if(sb.length() > 0){
			return sb.toString().split(",");
		}
		return null;
	}
	/**
	 * 获取连接设备相关状态,1在线 2 offline 3 未认证
	 * @return
	 */
	public static List<String[]> getConnectDevices(){
		IDevice[]  devices = bridge.getDevices();
		List<String[]> deviceList = new ArrayList<String[]>();
		for (int i = 0; i < devices.length; i++) {
			if(devices[i].isOnline()){
				deviceList.add(new String[]{devices[i].getSerialNumber(),"1"});
			}else if(devices[i].isOffline()){
				deviceList.add(new String[]{devices[i].getSerialNumber(),"2"});
			}else{
				deviceList.add(new String[]{devices[i].getSerialNumber(),"3"});
			}
		}
		return deviceList;
	}
	/**
	 * 获取所有已连接设备，不分是否在线
	 * @return
	 */
    public static IDevice[] getIDevices() {
    	return bridge.getDevices();
    }
    
    /**
     * 检查设备是否在线
     * @param devices
     * @return
     */
    public static boolean isCheckDeviceOnline(String[] devices){
    	if(devices == null){
    		return false;
    	}
    	String [] onLineDevices = getOnlineDevices();
    	if(onLineDevices == null ){
    		return false;
    	}

    	for(String device: devices){
    		boolean b = ArrayUtils.contains(onLineDevices, device);
    		if(b == false){
    			return false;
    		}
    	}
    	return true;
    }
    
    /**
     * 检查设备是否在线，并返回未在线设备
     * @param devices
     * @return
     */
    public static String getCheckDeviceOffline(String[] devices){
    	if(devices == null){
    		return null;
    	}
    	String [] onLineDevices = getOnlineDevices();
    	if(onLineDevices == null ){
    		return Joiner.on(",").join(devices);
    	}
    	List<String> result = new ArrayList<String>();
    	for(String device: devices){
    		boolean b = ArrayUtils.contains(onLineDevices, device);
    		if(b == false){
    			result.add(device);
    		}
    	}
    	return Joiner.on(",").join(result);
    }
    
	/**
	 * 获取手机硬件信息["ro.ril.oem.imei",
	 * "ro.build.version.sdk","ro.build.id",
	 * "ro.product.manufacturer","ro.product.model",
	 * "ro.product.name","ro.product.cpu.abi"]
	 * @param deviceid
	 * @return
	 */
	public static String getDeviceInfo(String deviceid){
		String cmdProp = cmdAdbProp.replace("deviceId", deviceid);
		String result = execAndReturn(cmdProp);
		DeviceInfo deviceInfo = new DeviceInfo();
		if(result != null){
			for(String tmp :result.split("\n")){
				String start = tmp.split(":")[0].trim();
				switch(start){
				case "[ro.serialno]":
					deviceInfo.serial = deviceid;
					break;
				case "[ro.ril.oem.imei]":
					deviceInfo.imei = tmp.split("\\]: \\[")[1].trim().replace("]", "");
					break;
				case "[ro.build.version.sdk]":
					deviceInfo.sdk_version = tmp.split("\\]: \\[")[1].trim().replace("]", "");
					break;
				case "[ro.modversion]": //锤子手机版本
					deviceInfo.sw_version = tmp.split("\\]: \\[")[1].trim().replace("]", "");
					break;
				case "[ro.build.display.id]":
					deviceInfo.sw_version_raw = tmp.split("\\]: \\[")[1].trim().replace("]", "");
					break;
				case "[ro.product.manufacturer]":
					deviceInfo.manufacturer = tmp.split("\\]: \\[")[1].trim().replace("]", "");
					break;
				case "[ro.product.model]":
					deviceInfo.model = tmp.split("\\]: \\[")[1].trim().replace("]", "");
					break;
				case "[ro.product.name]":
					deviceInfo.name = tmp.split("\\]: \\[")[1].trim().replace("]", "");
					break;
				case "[ro.product.cpu.abi]":
					deviceInfo.cpuAbi = tmp.split("\\]: \\[")[1].trim().replace("]", "");
					break;
				case "[ro.smartisan.tag]":
					deviceInfo.smartisan_tag = tmp.split("\\]: \\[")[1].trim().replace("]", "");
					break;
				case "[ro.build.date.utc]":
					deviceInfo.date_utc = tmp.split("\\]: \\[")[1].trim().replace("]", "");
					break;
				case "[ro.build.type]":
					deviceInfo.build_type = tmp.split("\\]: \\[")[1].trim().replace("]", "");
					break;
//				case "[gsm.operator.alpha]":
//					String sim = tmp.split("\\]: \\[")[1].trim().replace("]", "");
//					deviceInfo.sim1 = dealGsmType(sim);
//					break;
				default:
					break;
				}
			}
			deviceInfo.phase = getPhase(deviceid);
			deviceInfo.size = getDeviceSize(deviceid);
			if(deviceInfo.size == null){
				deviceInfo.size = getDeviceSizeByDisplay(deviceid);
			}
			return deviceInfo.toString();
		}
		return null;
	}
	
	
	private static String dealGsmType(String word){
		switch(word){
		case ",CHN-UNICOM":
		case ",China Unicom":
			return "46001";
		case ",CMCC":
			return "46000";
		default:
			return "46003";
		}
	}
	
	public static String getPhase(String deviceId){
		String cmdProp = "adb -s deviceId shell cat /sys/hwinfo/version_id".replace("deviceId", deviceId);
		String result = execAndReturn(cmdProp);
		if(result != null){
			for(String tmp :result.split("\n")){
				if(tmp.startsWith("version_id")){
					try{
						return tmp.split(":")[1];
					}catch(Exception e){
						
					}
				}
			}
		}
		return null;
	}
	
	/**
	 * 第三方包是否存在
	 * @param deviceid
	 * @param packageName
	 * @return
	 */
	public static boolean isAppInstalled(String deviceid,String packageName){
		String cmd = viewPackage.replaceAll("deviceId", deviceid) + packageName;
		String lines = execAndReturn(cmd);
		for(String tmp:lines.split("\n")){
			if(tmp.endsWith(packageName)){
				return true;
			}
		}
		return false;
	}
	
	/**
	 * 获取屏幕大小
	 * @param serial
	 * @return
	 */
	public static String getDeviceSize(String serial){
		String cmd = cmdScreenSize.replace("deviceId", serial);
		String result = execAndReturn(cmd);
		for(String tmp : result.split("\n")){
			if(tmp.startsWith("Physical size:")){
				return tmp.split(":")[1].trim();
			}
		}
		return null;
	}
	
	/**
	 * 获取屏幕大小
	 * @param serial
	 * @return
	 */
	public static String getDeviceSizeByDisplay(String serial){
		String cmd = String.format("adb -s %s shell dumpsys display", serial);
		String result = execAndReturn(cmd);
		for(String tmp : result.split("\n")){
			if(tmp.startsWith("mPhys=PhysicalDisplayInfo{")){
				return tmp.split(",")[0].replace("mPhys=PhysicalDisplayInfo{", "").replace(" ", "");
			}
		}
		return null;
	}

	/**
	 * 通过序列号，获取DDMS中设备实体
	 * 
	 * @param deviceId
	 * @return
	 */
	public static IDevice getDevice(String deviceId) {
		IDevice devices[] = bridge.getDevices();
		int deviceNum = 0;
		int deviceLen = devices.length;
		if (deviceLen == 0) {
			return null;
		}
		for (; deviceNum < deviceLen; deviceNum++) {
			if (deviceId.equalsIgnoreCase(devices[deviceNum].getSerialNumber())) {
				break;
			}
			if (deviceNum == (deviceLen - 1)
					&& !deviceId.equalsIgnoreCase(devices[deviceNum]
							.getSerialNumber())) {
				return null;
			}
		}

		return devices[deviceNum];

	}

	/**
	 * 断开整个adb调试桥
	 */
	public static void destory() {
		AndroidDebugBridge.disconnectBridge();
		AndroidDebugBridge.terminate();
		
	}

	/**
	 * 获取指定安卓设备中processName的PID号，返回值是一组或一个，以逗号分隔
	 * 
	 * @param deviceId
	 * @param processName
	 * @return
	 */
	public static String getAndroidPID(String deviceId, String processName) {
		if (deviceId == null || !(deviceId.length() > 0)) {
			return null;
		}
		String result = "";
		String tmpResult = execAndReturn(adbps.replace("deviceId", deviceId));
		for (String tmp : tmpResult.split("\n")) {
			if (tmp.endsWith(processName)) {
				result = result + tmp.split("\\s+")[1] + ",";
			}
		}
		if (result.length() > 0) {
			return result.substring(0, result.length() - 1);
		} else {
			return null;
		}
	}

	/**
	 * 根据进程名，终止指定设备的进程
	 * 
	 * @param deviceId
	 * @param pPids
	 * @throws IOException
	 */
	public static void killAndroidPID(String deviceId, String pPids) {
		if (pPids == null || deviceId == null) {
			return;
		}
		String[] pids = pPids.split(",");
		for (String tmp : pids) {
			exec(killPID.replace("deviceId", deviceId) + tmp, 10);
		}
	}
	/**
	 * 根据名称杀死进程
	 * @param deviceId
	 * @param packagename
	 */
	public static void killAndroidByName(String deviceId, String packagename){
		String pids = getAndroidPID(deviceId,packagename);
		killAndroidPID(deviceId, pids);
	}
	
	/**
	 * 重启adbserver
	 */
	public static void restartServer(){
		exec("adb start-server", 15);
	}

	/**
	 * 执行本地命令并返回结果
	 * 
	 * @param cmd
	 * @return
	 */
	public static String execAndReturn(String cmd) {
		return SystemCmdUtil.rexec(cmd);
	}

	/**
	 * 执行本地命令不返回
	 * 
	 * @param cmd
	 */
	public static void exec(String cmd, int timeout) {
		SystemCmdUtil.exec(cmd, timeout);
	}
	
	/**
	 * 检查android环境配置情况
	 * 
	 * @return
	 */
	public static String checkAndroidHome() {
		StringBuilder result = new StringBuilder();
		String osName = System.getProperty("os.name");
		String adbPath = System.getenv("android_home").replaceAll("\\\\", "/");
		String adb = osName.matches("(?i)windows.*") ? "adb.exe" : "adb";
		String tmp = adbPath + "/platform-tools/" + adb;
		result.append("AndroidHome路径: " + adbPath + "\n");
		File f = new File(tmp);
		if (!f.exists()) {
			result.append("ADB文件不存在" + "\n");
			result.append("检查失败");
		} else {
			result.append("ADB路径：" + tmp + "\n");
			result.append("检查成功");
		}
		return result.toString();

	}
	/**
	 * 转换端口
	 * @param device
	 * @param localport
	 * @param remotePort
	 */
	public static void forward(String device, int localport, int remotePort){
		String cmd = cmdForwardPort.replace("deviceId", device);
		exec(String.format(cmd, localport, remotePort), 5);
	}
	
	/**
	 * 移除端口
	 * @param localport
	 */
	public static void removeForward(int localport){
		exec("adb forward --remove tcp:"+localport, 5);
	}
	
	/**
	 * 转换端口
	 * @param device
	 * @param localport
	 * @param remotePort
	 */
	public static void forward(String device, int localport, String localabstract){
		String cmd = cmdForwardPortLocalabstract.replace("deviceId", device);
		exec(String.format(cmd, localport, localabstract), 5);
	}
	
	
	/**
	 * 获取forward list
	 * @return
	 */
	public static String getForwardList(){
		return ADBHelper.execAndReturn("adb forward --list");
	}

	/**
	 * 无线连接设备，返回连接成功或失败
	 * 
	 * @param ipAddress
	 * @return
	 */
	public static String connectDevice(String ipAddress) {
		String tmpStr = execAndReturn(cmdWireless + ipAddress);
		String result = null;
		for (String tmp : tmpStr.split("\n")) {
			if (tmp.startsWith("unable to connect")) {
				return null;
			} else {
				if (tmp.indexOf("already connected to ") >= 0
						|| tmp.indexOf("connected to ") >= 0) {
					result = tmp.replaceAll(
							"(already connected to )|(connected to )", "");
				}
			}

		}
		return result;
	}
	/**
	 * 清除所有设备端口
	 */
	public static void  clearForwardPort(){
		exec(cmdClearPort, 10);
	}

	/**
	 * 监听PC端设备连接，如果未连接30秒后超时
	 * 
	 * @param bridge
	 */
	private static void waitDeviceList() {
		int count = 0;
		while (bridge.hasInitialDeviceList() == false) {
			try {
				Thread.sleep(1000); // 如果没有获得设备列表，则等待
				count++;
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			if (count > 30) {
				// 设定时间超过30×1000 ms的时候为连接超时
				System.err.println("device connect Time out");
				break;
			}
		}
	}
	/**
	 * 安装apk
	 * @param deviceid
	 * @param apkPath
	 * @return
	 */
	public static Map<String, String> installApk(String deviceid, String apkPath){
		Map<String, String> data = new HashMap<String, String>();
		String cmd = cmdInstall.replace("deviceId", deviceid);
		String result = SystemCmdUtil.rexec(String.format(cmd, apkPath));
		if(Strings.isNullOrEmpty(result)){
			data.put("status", 1+"");
		}else{
			if(result.contains("Success")){
				data.put("status", 0+"");
			}else{
				data.put("status", 1+"");
			}
		}
		data.put("msg", result);
		return data;
	}
	
	/**
	 * push文件到/data/local/tmp
	 * @param deviceId
	 * @param filePath
	 */
	public static void pushFile(String deviceId, String filePath){
		String cmd = String.format("adb -s %s push \"%s\" /sdcard/", deviceId, filePath);
		exec(cmd, 2*60);
	}
	
	/**
	 * 获取版本号
	 * @param device
	 * @param packageName
	 * @return
	 */
	public static String getVersionCode(String device, String packageName) {
		String tmpStr = execAndReturn(String.format("adb -s %s shell dumpsys package %s", device, packageName));
		String result = null;
		for (String tmp : tmpStr.split("\n")){
			if (tmp.trim().length() > 0) {
				if (tmp.startsWith("versionCode=")) {
					result = tmp.trim().split(" ")[0].split("=")[1];
				}
			}
		}
		return result;
	}
	
	/**
	 * 获取设备是否加载完成，主界面是否已launch
	 * @param device
	 * @return
	 */
	public static boolean getDeviceLoadComplete(String device){
		String tmpStr = execAndReturn(String.format("adb -s %s shell getprop", device));
		String result = null;
		for (String tmp : tmpStr.split("\n")){
			if (tmp.trim().length() > 0) {
				if (tmp.startsWith("[sys.boot_completed]")) {
					result = tmp.split("\\]: \\[")[1].trim().replace("]", "");
				}
			}
		}
		if(result == null){
			return false;
		}
		return result.equals("1");
	}
	/**
	 * 判断手机是不是user版本
	 * @param device
	 * @return
	 */
	public static boolean isUser(String device){
		String tmpStr = execAndReturn(String.format("adb -s %s shell getprop", device));
		String result = null;
		for (String tmp : tmpStr.split("\n")){
			if (tmp.trim().length() > 0) {
				if (tmp.startsWith("[ro.build.type]")) {
					result = tmp.split("\\]: \\[")[1].trim().replace("]", "");
				}
			}
		}
		if(result == null){
			return false;
		}
		return result.equals("user");
	}
	/**
	 * 判断手机是不是root
	 * @param device
	 * @return
	 */
	public static boolean isRoot(String device){
		String tmpStr = execAndReturn(String.format("adb -s %s shell id", device));
		for (String tmp : tmpStr.split("\n")){
			if (tmp.trim().length() > 0) {
				if (tmp.contains("root")) {
					return true;
				}
			}
		}
		return false;
	}
	
	/**
	 * 检查端口使用情况
	 * @return
	 */
	public static boolean isCheckLocalPortUse(int port){
		Socket socket = null;
		try {
			socket = new Socket("127.0.0.1", port);
		} catch (Exception e) {
			return false;
		}finally{
			IOUtils.closeQuietly(socket);
		}
		return true;
	}
	
	public static void main(String[] args) {
		System.out.println(ADBHelper.getDeviceInfo("R4DEGAD6I7U4S4WO"));
	}
}
